//
//  NSObject+LYAdd.h
//  LYDevelopKit
//
//  Created by 李阳 on 2018/5/26.
//

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface NSObject (LYAdd)





#pragma mark Notification
/// 订阅通知
- (void)subscribeNotificationNamed:(NSString *)name block:(void (^)(NSNotification *notify))block;
/// 取消订阅通知
- (void)unsubscribeNotificationWithName:(NSString *)name;
/// 取消订阅过的所有通知
- (void)unsubscribeAllNotifications;



#pragma mark GCD

/**
 *  @brief  异步执行代码块
 *
 *  @param block 代码块
 */
- (void)performAsynchronous:(void(^)(void))block;
/**
 *  @brief  GCD主线程执行代码块
 *
 *  @param block 代码块
 *  @param shouldWait  是否同步请求
 */
- (void)performOnMainThread:(void(^)(void))block wait:(BOOL)shouldWait;

/**
 *  @brief  延迟执行代码块
 *
 *  @param seconds 延迟时间 秒
 *  @param block   代码块
 */
- (void)performAfter:(NSTimeInterval)seconds block:(void(^)(void))block;

#pragma mark Block

- (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay;
- (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay;
- (void)cancelBlock:(id)block;


@end


#pragma mark - Inject

#define bl_metamacro_stringify_(VALUE) # VALUE

#define bl_metamacro_stringify(VALUE) \
bl_metamacro_stringify_(VALUE)

#define bl_concrete \
optional \

#define bl_concreteprotocol(NAME) \
interface NAME ## _BLProtocolMethodContainer : NSObject < NAME > {} \
@end \
@implementation NAME ## _BLProtocolMethodContainer \
+ (void)load { \
if (!bl_addConcreteProtocol(objc_getProtocol(bl_metamacro_stringify(NAME)), self)) \
fprintf(stderr, "ERROR: Could not load concrete protocol %s\n", bl_metamacro_stringify(NAME)); \
} \
__attribute__((constructor)) \
static void bl_ ## NAME ## _inject (void) { \
bl_loadConcreteProtocol(objc_getProtocol(bl_metamacro_stringify(NAME))); \
}

BOOL bl_addConcreteProtocol (Protocol *protocol, Class methodContainer);
void bl_loadConcreteProtocol (Protocol *protocol);



